package com.ym.medical.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ym.core.redis.RedisKeyEnum;
import com.ym.core.redis.RedisKeyUtil;
import com.ym.core.redis.RedisUtil;
import com.ym.medical.service.IInquiryOrderSV;
import com.ym.medical.service.IOrderPoolSV;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * 操作Redis抢单池
 *
 * @author: 李涛
 * @version: 2019年05月10日 11:01
 */

@Service
@Transactional(rollbackFor = Exception.class)
public class OrderPoolSVImpl implements IOrderPoolSV {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private IInquiryOrderSV inquiryOrderSV;

    @Override
    public boolean put(RedisKeyEnum pool, String orderId, String... extra) {
        if (!(orderId.indexOf("mfs") > -1)) {
            orderId = RedisKeyUtil.keyBuilder(RedisKeyEnum.POOL_ORDER_ID, orderId);
        }
        return redisUtil.zSet(RedisKeyUtil.keyBuilder(pool, extra), orderId, 0.0);
    }

    @Override
    public boolean has(RedisKeyEnum pool, String orderId, String... extra) {
        if (!(orderId.indexOf("mfs") > -1)) {
            orderId = RedisKeyUtil.keyBuilder(RedisKeyEnum.POOL_ORDER_ID, orderId);
        }
        return redisUtil.zHasKey(RedisKeyUtil.keyBuilder(pool, extra), orderId);
    }

    @Override
    public long sizeByPool(RedisKeyEnum pool, String... extra) {
        return redisUtil.zSize(RedisKeyUtil.keyBuilder(pool, extra));
    }

    @Override
    public double scoreByOrder(RedisKeyEnum pool, String orderId, String... extra) {
        if (!(orderId.indexOf("mfs") > -1)) {
            orderId = RedisKeyUtil.keyBuilder(RedisKeyEnum.POOL_ORDER_ID, orderId);
        }
        return redisUtil.zScore(RedisKeyUtil.keyBuilder(pool, extra), orderId);
    }

    @Override
    public ArrayList<String> pullAllOrders(RedisKeyEnum pool, String... extra) {
        // 利用lua保证原子性,此处逻辑为获取所有的订单ID,且分值+1
        String getOrderAndRemoveForPool = "local orders = redis.call('ZRANGE',KEYS[1],ARGV[1],ARGV[2]);for i, v in ipairs(orders) do redis.call('ZINCRBY',KEYS[1],'1',v);end;return redis.call('ZRANGE',KEYS[1],ARGV[1],ARGV[2]);";
        Object execute = redisUtil.execute(getOrderAndRemoveForPool, Collections.singletonList(RedisKeyUtil.keyBuilder(pool, extra)), String.valueOf(0), String.valueOf(-1));
        return (ArrayList<String>) execute;
    }

    @Override
    public ArrayList<String> pullOrdersRandom(RedisKeyEnum pool, int takeNum, String... extra) {
        // 利用lua保证原子性,此处逻辑为获取头部分值较低订单,并+1
        String getOrderAndRemoveForPool = "local limit = 0;local counts = redis.call('ZCARD',KEYS[1]);local size = tonumber(ARGV[1]);if(size > counts) then size = counts; end;local orders = redis.call('ZRANGE',KEYS[1],limit,size);for i, v in ipairs(orders) do redis.call('ZINCRBY',KEYS[1],'1',v);end;return redis.call('ZRANGE',KEYS[1],limit,size);";
        Object execute = redisUtil.execute(getOrderAndRemoveForPool, Collections.singletonList(RedisKeyUtil.keyBuilder(pool, extra)), String.valueOf(takeNum - 1));
        return (ArrayList<String>) execute;
    }

    @Override
    public Set<String> listUnPullOrders(RedisKeyEnum pool, String... extra) {
        return redisUtil.zRangeByScore(RedisKeyUtil.keyBuilder(pool, extra), 0, 0);
    }

    @Override
    public long remove(RedisKeyEnum pool, String orderId, String... extra) {
        if (!(orderId.indexOf("mfs") > -1)) {
            orderId = RedisKeyUtil.keyBuilder(RedisKeyEnum.POOL_ORDER_ID, orderId);
        }
        return redisUtil.zSetRemove(RedisKeyUtil.keyBuilder(pool, extra), orderId);
    }

    @Override
    public void putDbOrder2Pool(RedisKeyEnum pool) {
        if (pool == RedisKeyEnum.GENERAL_DOCTOR_POOL) {
            // 全科医生抢单池.查询所有待接单状态的订单，加入到全科医生抢单池
            List<JSONObject> list = inquiryOrderSV.initGeneralPool();
            for (JSONObject order : list) {
                put(pool, order.getString("id"));
            }

        } else if (pool == RedisKeyEnum.SPECIALIST_DOCTOR_POOL) {
            // 专科医生抢单池
            List<JSONObject> list = inquiryOrderSV.initSpecialistPool();
            for (JSONObject order : list) {
                Long workId = order.getLong("workId");
                String orderId = order.getString("id");
                put(pool, orderId, "WORK", workId.toString());
            }
        }
    }
}
